# -*- python -*-
# ex: set syntax=python:
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# READ THIS:
# See http://dev.chromium.org/developers/testing/chromium-build-infrastructure

import socket

# These modules come from scripts, which must be in the PYTHONPATH.
from master import master_config
from master import master_utils
from master import slaves_list
from master.builders_pools import BuildersPools
from master.factory import annotator_factory
from master.factory import chromium_factory
from master.try_job_http import TryJobHTTP
from master.try_job_rietveld import TryJobRietveld
from master.try_job_svn import TryJobSubversion

import config
import master_site_config

ActiveMaster = master_site_config.ChromiumPerfTryServer


MAIL_NOTIFIER = ActiveMaster.is_production_host
UPDATE_CODEREVIEW = ActiveMaster.is_production_host
LISTEN_TO_RIETVELD = ActiveMaster.is_production_host
LISTEN_TO_SVN = ActiveMaster.svn_url and ActiveMaster.is_production_host

# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {}

config.DatabaseSetup(c, require_dbconfig=ActiveMaster.is_production_host)

c['change_source'] = []

# Avoid merging requests.
c['mergeRequests'] = False

# TODO: Delete Chromium factory instances once bisect is fully functional with
# recipes.
m_chromium_win = chromium_factory.ChromiumFactory(
    'src/build',
    target_platform='win32',
    full_checkout=True)

m_chromium_linux = chromium_factory.ChromiumFactory(
    'src/out',
    target_platform='linux2',
    full_checkout=True)

m_chromium_mac = chromium_factory.ChromiumFactory(
    'src/xcodebuild',
    target_platform='darwin',
    full_checkout=True)

m_chromium_mac_ninja = chromium_factory.ChromiumFactory(
    'src/out',
    target_platform='darwin',
    full_checkout=True)

m_chromium_android = chromium_factory.ChromiumFactory(
    '',
    target_platform='linux2',
    nohooks_on_update=True,
    target_os='android',
    full_checkout=True)

# TODO: Delete this method once bisect is fully functional with recipes.
def GenAndroidBisectBot(device):
  """Generates and registers an android builder along with its slave(s)."""
  target = 'Release'
  builder_name = 'android_%s_perf_bisect' % device
  slavebuilddir = 'android'
  max_time_seconds = 24 * 60 * 60
  options = []
  tests = []
  annotation_script = 'src/build/android/buildbot/bb_run_bot.py'
  factory_properties = {
      'android_bot_id': 'perf-bisect-builder-tests-dbg-%s' % device,
      'gclient_timeout': 3600
  }

  assert tests is not None or annotation_script, (
      'Must either specify tests or use an annotation script')

  factory_properties = (factory_properties or {}).copy()
  factory_properties.setdefault('gclient_env', {})
  factory_properties['gclient_env'].setdefault('GYP_DEFINES', '')
  if not 'fastbuild=0' in factory_properties['gclient_env']['GYP_DEFINES']:
    factory_properties['gclient_env']['GYP_DEFINES'] += ' fastbuild=1'

  build_tool = []
  factory = m_chromium_android

  factory_properties['gclient_env']['GYP_GENERATORS'] = 'ninja'
  build_tool.append('--build-tool=ninja')

  options = build_tool + ['--clobber-post-fail'] + (options or [])

  compile_timeout = 3600
  assert annotation_script
  # Note new slave type AnnotatedTrybot; we don't want a compile step added
  # in gclient_factory.py.
  builder_factory = factory.ChromiumAnnotationFactory(
      slave_type='AnnotatedTrybot', target=target, tests=tests,
      options=options,
      compile_timeout=compile_timeout,
      factory_properties=factory_properties,
      annotation_script=annotation_script, maxTime=max_time_seconds)
  builder_info = {
    'name': builder_name,
    'factory': builder_factory,
  }
  if slavebuilddir:
    builder_info['slavebuilddir'] = slavebuilddir
  return builder_info


def GenRecipeBisectBuilder(name, recipe, upload_dir, timeout=2400):
  properties = {
      'append_deps_patch_sha': True,
      'build_url': master_config.GetGSUtilUrl('chrome-perf', upload_dir)}
  return {
      'name': name,
      'factory': annotator_factory.AnnotatorFactory(ActiveMaster).BaseFactory(
          factory_properties=properties,
          recipe=recipe,
          timeout=timeout)}

# TODO: May be we should merge this method with GenRecipeBisectBuilder by
# adding a way to distinguish between builder and bisector bots.
def GenRecipeBisectBot(name, recipe, timeout=3600):
  return {
      'name': name,
      'factory': annotator_factory.AnnotatorFactory(ActiveMaster).BaseFactory(
          recipe=recipe,
          timeout=timeout,
          max_time=24 * 60 * 60)}

# TODO: Delete this method once bisect is fully functional with recipes.
def GenBisectBot(name, factory):
  return {'name': name,
          'slavebuilddir': name,
          'factory': factory.ChromiumFactory(
              slave_type='Bisect',
              tests=[
                'bisect_revisions',
              ]),
         }


# Recipe-based builders
b_android_perf_builder = GenRecipeBisectBuilder(
    'android_perf_bisect_builder', 'android/builder', 'android_perf_rel')
b_android_arm64_perf_bisect_builder = GenRecipeBisectBuilder(
    'android_arm64_perf_bisect_builder', 'android/builder',
    'android_perf_rel_arm64')
b_linux_perf_builder = GenRecipeBisectBuilder(
    'linux_perf_bisect_builder', 'chromium', 'Linux Builder')
b_mac_perf_builder = GenRecipeBisectBuilder(
    'mac_perf_bisect_builder', 'chromium', 'Mac Builder')
b_win_perf_builder = GenRecipeBisectBuilder(
    'win_perf_bisect_builder', 'chromium', 'Win Builder', timeout=4800)
b_win_x64_perf_builder = GenRecipeBisectBuilder(
    'win_x64_perf_bisect_builder', 'chromium', 'Win x64 Builder', timeout=4800)
b_linux_perf_bisector = GenRecipeBisectBuilder(
    'linux_perf_bisector', 'bisect', 'Linux Bisector')
b_linux_perf_tester = GenRecipeBisectBuilder(
    'linux_perf_tester', 'chromium', 'Linux Tester')

# non-Android bisect bots with recipes
b_linux_perf_bisect = GenRecipeBisectBot(
    'linux_perf_bisect', 'bisection/desktop_bisect')
b_mac_perf_bisect = GenRecipeBisectBot(
    'mac_perf_bisect', 'bisection/desktop_bisect')
b_mac_10_9_perf_bisect = GenRecipeBisectBot(
    'mac_10_9_perf_bisect', 'bisection/desktop_bisect')
b_win_perf_bisect = GenRecipeBisectBot(
    'win_perf_bisect', 'bisection/desktop_bisect')
b_win_xp_perf_bisect = GenRecipeBisectBot(
    'win_xp_perf_bisect', 'bisection/desktop_bisect')
b_win_8_perf_bisect = GenRecipeBisectBot(
    'win_8_perf_bisect', 'bisection/desktop_bisect')
b_win_x64_perf_bisect = GenRecipeBisectBot(
    'win_x64_perf_bisect', 'bisection/desktop_bisect')
b_win_x64_ati_gpu_perf_bisect = GenRecipeBisectBot(
    'win_x64_ati_gpu_perf_bisect', 'bisection/desktop_bisect')
b_win_x64_nvidia_gpu_perf_bisect = GenRecipeBisectBot(
    'win_x64_nvidia_gpu_perf_bisect', 'bisection/desktop_bisect')


# Android bisect bots with recipes.
b_android_one_perf_bisect = GenRecipeBisectBot(
    'android_one_perf_bisect', 'bisection/android_bisect')
b_android_motoe_perf_bisect = GenRecipeBisectBot(
    'android_motoe_perf_bisect', 'bisection/android_bisect')
b_android_nexus4_perf_bisect = GenRecipeBisectBot(
    'android_nexus4_perf_bisect', 'bisection/android_bisect')
b_android_nexus5_perf_bisect = GenRecipeBisectBot(
    'android_nexus5_perf_bisect', 'bisection/android_bisect')
b_android_nexus6_perf_bisect = GenRecipeBisectBot(
    'android_nexus6_perf_bisect', 'bisection/android_bisect')
b_android_nexus7_perf_bisect = GenRecipeBisectBot(
    'android_nexus7_perf_bisect', 'bisection/android_bisect')
b_android_nexus9_perf_bisect = GenRecipeBisectBot(
    'android_nexus9_perf_bisect', 'bisection/android_bisect')
b_android_nexus10_perf_bisect = GenRecipeBisectBot(
    'android_nexus10_perf_bisect', 'bisection/android_bisect')

c['builders'] = [
  b_android_perf_builder,
  b_android_arm64_perf_bisect_builder,
  b_linux_perf_builder,
  b_mac_perf_builder,
  b_win_perf_builder,
  b_win_x64_perf_builder,
  b_linux_perf_bisect,
  b_mac_perf_bisect,
  b_mac_10_9_perf_bisect,
  b_win_perf_bisect,
  b_win_x64_perf_bisect,
  b_win_x64_ati_gpu_perf_bisect,
  b_win_x64_nvidia_gpu_perf_bisect,
  b_win_xp_perf_bisect,
  b_win_8_perf_bisect,
  b_android_motoe_perf_bisect,
  b_android_one_perf_bisect,
  b_android_nexus4_perf_bisect,
  b_android_nexus5_perf_bisect,
  b_android_nexus6_perf_bisect,
  b_android_nexus7_perf_bisect,
  b_android_nexus9_perf_bisect,
  b_android_nexus10_perf_bisect,
  b_linux_perf_tester,
  b_linux_perf_bisector,
]

slaves = slaves_list.SlavesList('slaves.cfg', 'ChromiumPerfTryServer')

for builder in c['builders']:
  builder['slavenames'] = slaves.GetSlavesName(builder=builder['name'])
  builder.setdefault('auto_reboot', ActiveMaster.is_production_host)

c['slaves'] = master_utils.AutoSetupSlaves(c['builders'],
                                           config.Master.GetBotPassword())

master_utils.VerifySetup(c, slaves)

c['schedulers'] = []

pools = BuildersPools('chrome')
pools['chrome'].extend([builder['name'] for builder in c['builders']])

code_review_sites = {'chrome': ActiveMaster.code_review_site}

c['schedulers'].append(TryJobHTTP(
      name='try_job_http',
      port=ActiveMaster.try_job_port,
      code_review_sites=code_review_sites,
      pools=pools))

if LISTEN_TO_RIETVELD:
  c['schedulers'].append(TryJobRietveld(
        name='try_job_rietveld',
        code_review_sites=code_review_sites,
        pools=pools,
        project='chrome',
        filter_master=True))

if LISTEN_TO_SVN:
  c['schedulers'].append(TryJobSubversion(
      name='try_job_svn',
      svn_url=ActiveMaster.svn_url,
      code_review_sites=code_review_sites,
      pools=pools))

# Buildbot master url:
# Must come before AutoSetupMaster().
if ActiveMaster.is_production_host:
  c['buildbotURL'] = ActiveMaster.buildbot_url
else:
  c['buildbotURL'] = 'http://%s:%d/' % (
      socket.getfqdn(), ActiveMaster.master_port)

# Adds common status and tools to this master.
# Use our own mail notifier.
master_utils.AutoSetupMaster(c, ActiveMaster, False)

if MAIL_NOTIFIER:
  # Add a dumb MailNotifier first so it will be used for BuildSlave with
  # notify_on_missing set when they go missing.
  from buildbot.status import mail
  c['status'].append(mail.MailNotifier(
      fromaddr=ActiveMaster.from_address,
      builders=[],
      relayhost=config.Master.smtp,
      lookup=master_utils.UsersAreEmails()))

  from master import chromium_notifier
  c['status'].append(chromium_notifier.ChromiumNotifier(
      fromaddr=ActiveMaster.from_address,
      categories_steps={'': ['update_scripts']},
      relayhost=config.Master.smtp,
      status_header=
          '%(steps)s failed on slave "%(slavename)s" for builder "%(builder)s"',
      subject='%(steps)s failed on trybot %(slavename)s on %(date)s',
      sendToInterestedUsers=False,
      extraRecipients=['chrome-troopers+tryalert@google.com'],
      use_getname=True,
      enable_mail=ActiveMaster.is_production_host))

  # Try job result emails.
  from master.try_mail_notifier import TryMailNotifier
  c['status'].append(TryMailNotifier(
      fromaddr=ActiveMaster.from_address,
      reply_to=ActiveMaster.reply_to,
      subject="try %(result)s for %(reason)s @ r%(revision)s",
      mode='all',
      relayhost=config.Master.smtp,
      lookup=master_utils.UsersAreEmails()))
else:
  from buildbot.status import mail
  c['status'].append(mail.MailNotifier(
      fromaddr=ActiveMaster.from_address,
      builders=[],
      relayhost=config.Master.smtp,
      extraRecipients=['robertocn@chromium.org']))

  from master import chromium_notifier
  c['status'].append(chromium_notifier.ChromiumNotifier(
      fromaddr=ActiveMaster.from_address,
      categories_steps={'': ['update_scripts']},
      relayhost=config.Master.smtp,
      status_header=
          '%(steps)s failed on slave "%(slavename)s" for builder "%(builder)s"',
      subject='%(steps)s failed on trybot %(slavename)s on %(date)s',
      sendToInterestedUsers=False,
      use_getname=True,
      extraRecipients=['robertocn@chromium.org']))


if UPDATE_CODEREVIEW:
  from master.status_push import TryServerHttpStatusPush
  c['status'].append(
      TryServerHttpStatusPush(serverUrl=ActiveMaster.code_review_site))

# The followings are what is kept on disk.
# Keep last try jobs, the default is too low. Must keep at least a few days
# worth of try jobs. 3000 is not even a full day but the server is full. Keep
# more build objects than log since they are much smaller.
c['buildHorizon'] = 6000
c['logHorizon'] = 3000
# Must be at least 2x the number of slaves.
c['eventHorizon'] = 200
c['logCompressionLimit'] = False

# Adjust the buildCaches to be 3x the number of slaves per builder.
c['autoBuildCacheRatio'] = 3

c['projectURL'] = 'http://dev.chromium.org/developers/testing/try-server-usage'

# vi: set ts=4 sts=2 sw=2 et:
